/*
 *Copyright (c) [2019-2020]  C2comm, Inc.  All rights reserved.
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; If not, see <https://www.gnu.org/licenses/>
 */

/*
 *Vendor: C2comm
 *Version: 1.0
 *Filename: SMCliqueDetect.v
 *Target Device: Altera
 *Author : sunxiaotian@c2comm.cn
*/


`timescale 1ns/1ps
module SMCliqueDetect(
    input  wire         SYS2CORE_clk,
    input  wire         SYS2CORE_rst_n,
                       
    input  wire [348:0] CONF2CORE_sm_static_conf,
    output wire [332:0] CORE2MON_sm_state,
    input  wire [19 :0] G_local_clk,
    input  wire [5  :0] G_integration_cycle,
    
    input  wire         SC2CD_sync_des_valid,
    input  wire [8 :0]  SC2CD_sync_des,
    
    output reg  [14:0]  CD2SC_clique_in,
	
    input  wire [76:0]  G_current_state,
	
	input  wire [90:0]  G_pcf_des,
	input  wire         G_pcf_des_valid
);
//***************************************************
//            中间变量声明区域
//***************************************************

reg [7:0] localSyncMembership;
reg [7:0] localAsyncMembership[1:0];

wire [7:0] cur_localSyncMembership;
wire [7:0] cur_localAsyncMembership[1:0];

//***************************************************
//       状态统计信息处理
//***************************************************
assign CORE2MON_sm_state[241:0] = 242'b0;
assign CORE2MON_sm_state[249:242] = localAsyncMembership[1];
assign CORE2MON_sm_state[257:250] = localAsyncMembership[0];
assign CORE2MON_sm_state[265:258] = localSyncMembership[7:0];
assign CORE2MON_sm_state[332:266] = 67'b0;


assign cur_localSyncMembership = localSyncMembership[0]+localSyncMembership[1]+
									localSyncMembership[2]+localSyncMembership[3]+
									localSyncMembership[4]+localSyncMembership[5]+
									localSyncMembership[6]+localSyncMembership[7];
									
assign cur_localAsyncMembership[0] = localAsyncMembership[0][0]+localAsyncMembership[0][1]+
									localAsyncMembership[0][2]+localAsyncMembership[0][3]+
									localAsyncMembership[0][4]+localAsyncMembership[0][5]+
									localAsyncMembership[0][6]+localAsyncMembership[0][7];
									
assign cur_localAsyncMembership[1] = localAsyncMembership[1][0]+localAsyncMembership[1][1]+
									localAsyncMembership[1][2]+localAsyncMembership[1][3]+
									localAsyncMembership[1][4]+localAsyncMembership[1][5]+
									localAsyncMembership[1][6]+localAsyncMembership[1][7];

//***************************************************
//            update membership
//***************************************************

always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        localSyncMembership[7:0] <= 8'b0;
		localAsyncMembership[0][7:0] <= 8'b0;
		localAsyncMembership[1][7:0] <= 8'b0;
    end
    else begin
		/*Update the value of membership based on SC2CD_sync_des*/
		if(SC2CD_sync_des_valid == 1'b1) begin
			if(SC2CD_sync_des[8] == 1'b0) begin
				localSyncMembership[7:0] <= SC2CD_sync_des[7:0];
			end
			else if(SC2CD_sync_des[8] == 1'b1 && (G_local_clk[19:0]>(CONF2CORE_sm_static_conf[329:310]-CONF2CORE_sm_static_conf[303:285]))) begin
				localAsyncMembership[0][7:0] <= localAsyncMembership[0][7:0] | SC2CD_sync_des[7:0];
				localAsyncMembership[1][7:0] <= localAsyncMembership[1][7:0] | SC2CD_sync_des[7:0];
			end
			else if(SC2CD_sync_des[8] == 1'b1 && (G_local_clk[19:0]<=(CONF2CORE_sm_static_conf[329:310]-CONF2CORE_sm_static_conf[303:285]))) begin
				if(G_integration_cycle[0]== 1'b0) begin
					localAsyncMembership[0][7:0] <= localAsyncMembership[0][7:0] | SC2CD_sync_des[7:0];
				end
				else begin
					localAsyncMembership[1][7:0] <= localAsyncMembership[1][7:0] | SC2CD_sync_des[7:0];
				end
			end
		end
		/*Update the value of membership based on G_pcf_des and type=IN、SM_INTEGRATE、SM_UNSYNC*/ //
		if(G_pcf_des_valid == 1'b1 && G_pcf_des[17:16] == 2'b10 && (G_current_state[76:69] == 8'b0000_0001 || G_current_state[76:69] == 8'b0000_0100)) begin
			if(G_pcf_des[38] == 1'b1 || G_pcf_des[39] == 1'b1 || G_pcf_des[40] == 1'b1 || G_pcf_des[41] == 1'b1) begin
				localSyncMembership[7:0] <= G_pcf_des[15:8];
				localAsyncMembership[0][7:0] <= 8'b0;
				localAsyncMembership[1][7:0] <= 8'b0;
			end
		end
		/*Update the value of membership based on smc_async_eval_pit,SM_TENTATIVE_SYNC,SM_SYNC,SM_STABLE_SYNC*/
		if(G_current_state[76:69] == 8'b0010_0000 || G_current_state[76:69] == 8'b0100_0000 || G_current_state[76:69] == 8'b1000_0000) begin
			if(G_local_clk[19:0] == CONF2CORE_sm_static_conf[59:40] ) begin 
				//localSyncMembership[7:0] <= 8'b0;
			end
			else if(G_local_clk[19:0] == CONF2CORE_sm_static_conf[39:20]) begin 
				localSyncMembership[7:0] <= 8'b0;
				if(G_integration_cycle[0]==1'b0) begin
					localAsyncMembership[0][7:0] <= 8'b0;
				end
				else begin
					localAsyncMembership[1][7:0] <= 8'b0;
				end
			end
		end
		/*Update the value of membership based on G_current_state*/
		case(G_current_state[76:69])
			8'b0000_0001:begin //SM_INTEGRATE
				case(G_current_state[68:62])
					7'b0001_000:begin //C0_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					7'b0010_000:begin //C1_S
						localSyncMembership[7:0] <= 8'b1;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					default:;
				endcase
			end
			8'b0000_0010:; //SM_WAIT_4_CYCLE_START
			8'b0000_0100:begin //SM_UNSYC
				case(G_current_state[55:47])
					9'b000001_000:begin //C0_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					9'b000010_000:begin //C1_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					9'b000100_000:begin //C2_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					9'b001000_000:begin //C3_S
						localSyncMembership[7:0] <= 8'b1;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					default:;
				endcase
			end
			8'b0000_1000:begin //SM_FLOOD
				case(G_current_state[46:39])
					8'b00001_000:begin //C0_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					8'b00010_000:begin //C1_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					8'b00100_000:begin //C2_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					8'b01000_000:begin //C3_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					8'b10000_000:begin //C4_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					default:;
				endcase
			end
			8'b0001_0000:begin //SM_WAIT_4_CYCLE_START_CS
				case(G_current_state[38:33])
					6'b001_000:begin //C0_S
						localSyncMembership[7:0] <= 8'b1;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					6'b010_000:begin //C1_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					6'b100_000:begin //C2_S
						localSyncMembership[7:0] <= 8'b1;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					default:;
				endcase
			end
			8'b0010_0000:begin //SM_TENTATIVE_SYNC
				case(G_current_state[32:22])
					11'b00000001_000:begin //C0_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					11'b00000100_000:begin //C2_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					11'b10000000_000:begin //C7_S
						localSyncMembership[7:0] <= 8'b1;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					default:;
				endcase
			end
			8'b0100_0000:begin //SM_SYNC
				case(G_current_state[21:10])
					12'b000000001_000:begin //C0_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					12'b000000100_000:begin //C2_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					12'b000001000_000:begin //C3_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					12'b100000000_000:begin //C8_S
						localSyncMembership[7:0] <= 8'b1;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					default:;
				endcase
			end
			8'b1000_0000:begin //SM_STABLE
				case(G_current_state[9:0])
					10'b0000001_000:begin //C0_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					10'b0001000_000:begin //C3_S
						localSyncMembership[7:0] <= 8'b0;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					10'b1000000_000:begin //C6_S
						localSyncMembership[7:0] <= 8'b1;
						if(G_integration_cycle[0]==1'b0) begin
							localAsyncMembership[0][7:0] <= 8'b0;
						end
						else begin
							localAsyncMembership[1][7:0] <= 8'b0;
						end
					end
					default:;
				endcase
			end
			default:;
		endcase
    end
end


/***************************************************
//            clique detect
SYNC Clique Detect:
if ( ( local_sync_membership < state.sync_threshold ) then
  return TRUE;

ASYNC Clique Detect:
if ( ( local_async_membership[0] >= state.async_threshold ) or 
( local_async_membership[1] >= state.async_threshold ) )
then
   return TRUE;

Relative Clique Detect:
if ( (local_sync_membership <= local_async_membership[0])  or  (local_sync_membership <= local_async_membership[1]) )
then
   return TRUE;

****************************************************/
always @(*) begin
	CD2SC_clique_in[0] = (cur_localSyncMembership < CONF2CORE_sm_static_conf[123:120])?1'b1:1'b0;
	CD2SC_clique_in[1] = (cur_localSyncMembership >= CONF2CORE_sm_static_conf[123:120] && cur_localSyncMembership < CONF2CORE_sm_static_conf[119:116])?1'b1:1'b0;
	CD2SC_clique_in[2] = (cur_localSyncMembership >= CONF2CORE_sm_static_conf[119:116])?1'b1:1'b0;
	CD2SC_clique_in[3] = (cur_localSyncMembership >= CONF2CORE_sm_static_conf[123:120] && cur_localSyncMembership < CONF2CORE_sm_static_conf[119:116])?1'b1:1'b0;
	CD2SC_clique_in[4] = (cur_localSyncMembership < CONF2CORE_sm_static_conf[111:108] && cur_localSyncMembership > 0)?1'b1:1'b0;
	CD2SC_clique_in[5] = (cur_localSyncMembership < CONF2CORE_sm_static_conf[111:108] && cur_localSyncMembership == 0)?1'b1:1'b0;
	CD2SC_clique_in[6] = (cur_localSyncMembership >= CONF2CORE_sm_static_conf[111:108])?1'b1:1'b0;
	CD2SC_clique_in[7] = (cur_localSyncMembership < CONF2CORE_sm_static_conf[111:108])?1'b1:1'b0;
	CD2SC_clique_in[8] = (cur_localSyncMembership >= CONF2CORE_sm_static_conf[103:100])?1'b1:1'b0;
    if(G_integration_cycle[0]==1'b0) begin
		CD2SC_clique_in[9] = (cur_localAsyncMembership[0] >= CONF2CORE_sm_static_conf[127:124] || cur_localAsyncMembership[0] >= cur_localSyncMembership)?1'b1:1'b0;
		CD2SC_clique_in[10] = ~((cur_localAsyncMembership[0] >= CONF2CORE_sm_static_conf[127:124] || cur_localAsyncMembership[0] >= cur_localSyncMembership)?1'b1:1'b0);
		CD2SC_clique_in[11] = (cur_localAsyncMembership[0] >= CONF2CORE_sm_static_conf[115:112] || cur_localAsyncMembership[0] >= cur_localSyncMembership)?1'b1:1'b0;
		CD2SC_clique_in[12] = ~((cur_localAsyncMembership[0] >= CONF2CORE_sm_static_conf[115:112] || cur_localAsyncMembership[0] >= cur_localSyncMembership)?1'b1:1'b0);
		CD2SC_clique_in[13] = (cur_localAsyncMembership[0] >= CONF2CORE_sm_static_conf[107:104] || cur_localAsyncMembership[0] >= cur_localSyncMembership)?1'b1:1'b0;
		CD2SC_clique_in[14] = ~((cur_localAsyncMembership[0] >= CONF2CORE_sm_static_conf[107:104] || cur_localAsyncMembership[0] >= cur_localSyncMembership)?1'b1:1'b0);
	end
	else begin
		CD2SC_clique_in[9] = (cur_localAsyncMembership[1] >= CONF2CORE_sm_static_conf[127:124] || cur_localAsyncMembership[1] >= cur_localSyncMembership)?1'b1:1'b0;
		CD2SC_clique_in[10] = ~((cur_localAsyncMembership[1] >= CONF2CORE_sm_static_conf[127:124] || cur_localAsyncMembership[1] >= cur_localSyncMembership)?1'b1:1'b0);
		CD2SC_clique_in[11] = (cur_localAsyncMembership[1] >= CONF2CORE_sm_static_conf[115:112] || cur_localAsyncMembership[1] >= cur_localSyncMembership)?1'b1:1'b0;
		CD2SC_clique_in[12] = ~((cur_localAsyncMembership[1] >= CONF2CORE_sm_static_conf[115:112] || cur_localAsyncMembership[1] >= cur_localSyncMembership)?1'b1:1'b0);
		CD2SC_clique_in[13] = (cur_localAsyncMembership[1] >= CONF2CORE_sm_static_conf[107:104] || cur_localAsyncMembership[1] >= cur_localSyncMembership)?1'b1:1'b0;
		CD2SC_clique_in[14] = ~((cur_localAsyncMembership[1] >= CONF2CORE_sm_static_conf[107:104] || cur_localAsyncMembership[1] >= cur_localSyncMembership)?1'b1:1'b0);
	end
	
end

endmodule